专题信息图标导航响应式

<script setup>
import {onMounted, ref} from 'vue'
import {DataAnalysis, FirstAidKit, MagicStick, Refresh, UserFilled} from '@element-plus/icons-vue'
import axios from 'axios';

// 1. 轮播图 mock 数据
const carouselList = ref([
  {imageUrl: 'https://picsum.photos/800/240?1', description: '轮播图一：专题介绍'},
  {imageUrl: 'https://picsum.photos/800/240?2', description: '轮播图二：最新动态'},
  {imageUrl: 'https://picsum.photos/800/240?3', description: '轮播图三：资源推荐'},
])

// 2. 图文混编列表 mock 数据
const mixedList = ref([
  {imageUrl: 'https://picsum.photos/200/120?1', title: '图文一', description: '这是图文一的描述内容。'},
  {imageUrl: 'https://picsum.photos/200/120?2', title: '图文二', description: '这是图文二的描述内容。'},
  {imageUrl: 'https://picsum.photos/200/120?3', title: '图文三', description: '这是图文三的描述内容。'},
])

// 3. 图标导航 mock 数据
const iconNav = ref([
  {icon: DataAnalysis, label: '数据分析', link: '#'},
  {icon: MagicStick, label: '创新研究', link: '#'},
  {icon: UserFilled, label: '团队管理', link: '#'},
  {icon: UserFilled, label: '全球趋势', link: '#'},
  {icon: Refresh, label: '可持续发展', link: '#'},
  {icon: FirstAidKit, label: '健康生活', link: '#'},
])

// 4. 时间轴 mock 数据
const timelineList = ref([
  {time: '2024-05-01', title: '专题启动', content: '项目正式启动，组建团队。', color: '#409EFF'},
  {time: '2024-05-10', title: '阶段成果', content: '完成初步方案设计。', color: '#67C23A'},
  {time: '2024-05-20', title: '上线发布', content: '专题页面正式上线。', color: '#E6A23C'},
])

// 5. 表格 mock 数据
const tableData = ref([
  {resourceName: '资源A', resourceType: '文档', date: '2024-05-01', description: 'A资源描述'},
  {resourceName: '资源B', resourceType: '图片', date: '2024-05-02', description: 'B资源描述'},
  {resourceName: '资源C', resourceType: '链接', date: '2024-05-03', description: 'C资源描述'},
])

// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(100)

const handleSizeChange = (val) => {
  pageSize.value = val
  // 这里可以添加获取分页的逻辑
}

const handleCurrentChange = (val) => {
  currentPage.value = val
  // 这里可以添加获取分页的逻辑
}

// 图标颜色
const iconStyle = (idx) => {
  switch (idx) {
    case 0:
      return {
        color: '#409EFF'
      }
    case 1:
      return {
        color: '#36CFC9'
      }
    case 2:
      return {
        color: '#FF7D00'
      }
    case 3:
      return {
        color: '#A855F7'
      }
    case 4:
      return {
        color: '#22C55E'
      }
    case 5:
      return {
        color: '#F7A4A3'
      }
  }
}

// 获取资源类型标签样式
const getTagType = (type) => {
  switch (type) {
    case '文档':
      return '' // 默认蓝色
    case '图片':
      return 'success' // 绿色
    case '链接':
      return 'danger' // 红色
    default:
      return 'warning' // 黄色
  }
}

// 图标背景颜色
const iconBgStyle = (idx) => {
  switch (idx) {
    case 0:
      return {
        backgroundColor: '#E7EEFF'
      }
    case 1:
      return {
        backgroundColor: '#EBFAF9'
      }
    case 2:
      return {
        backgroundColor: '#FFF2E5'
      }
    case 3:
      return {
        backgroundColor: '#F3E8FF'
      }
    case 4:
      return {
        backgroundColor: '#DCFCE7'
      }
    case 5:
      return {
        backgroundColor: '#FEE2E2'
      }
  }
}

// 获取轮播图
const getBannersList = () => {
  axios({
    url: '/api/banner/homepage',
    method: 'get',
  }).then(res => {
    console.log('获取轮播图的结果是--->', res);
    if (res.data.code === 200) {
      carouselList.value = res.data.data;
      console.log('carouselList', carouselList);
    }
  })
}

// 获取图文列表
const getArticleList = () => {
  axios({
    url: '/api/article/homepage',
    method: 'get',
  }).then(res => {
    console.log('获取图文列表的结果是--->', res);
    mixedList.value = res.data.data;
    console.log('mixedList', mixedList);
  })
}

// 获取资源表格
const getResourceList = () => {
  axios({
    url: '/api/resource/homepage',
    method: 'get',
  }).then(res => {
    console.log('获取资源表格的结果是--->', res);
    tableData.value = res.data.data;
    console.log('tableData', tableData);
  })
}

// 挂在结束钩子函数
onMounted(() => {
  getBannersList();
  getArticleList();
  getResourceList();
})

function handleView(row) {
  // 这里可以弹窗或跳转，演示用 alert
  alert(`查看：${row.resourceName}`)
}

const isTextOverflow = (text) => {
  const el = document.createElement('div');
  el.style.display = '-webkit-box';
  el.style.webkitLineClamp = '3';
  el.style.webkitBoxOrient = 'vertical';
  el.style.overflow = 'hidden';
  el.style.width = '200px';
  el.innerText = text;
  document.body.appendChild(el);
  const isOverflow = el.scrollHeight > el.clientHeight;
  document.body.removeChild(el);
  return isOverflow;
}
</script>

<template>
  <div class="app-bg">
    <div class="topic-info">
      <!-- 1. 轮播图 -->
      <el-carousel height="320px" indicator-position="outside">
        <el-carousel-item v-for="(item, idx) in carouselList" :key="idx">
          <div class="carousel-img-wrapper">
            <img :src="item.imageUrl" class="carousel-img"/>
            <div class="carousel-caption">{{ item.description }}</div>
          </div>
        </el-carousel-item>
      </el-carousel>

      <!-- 2. 图文混编列表 -->
      <div class="section-title">图文列表</div>
      <el-row :gutter="24">
        <el-col :span="8" :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-for="(item, idx) in mixedList" :key="idx">
          <el-card :body-style="{ padding: '12px' }">
            <img :src="item.imageUrl" class="mixed-img"/>
            <div class="mixed-title">{{ item.title }}</div>
            <div class="mixed-desc">{{ item.description }}</div>
          </el-card>
        </el-col>
      </el-row>

      <!-- 3. 图标导航 -->
      <div class="section-title">图标导航</div>
      <el-row :gutter="32" class="icon-nav">
        <el-col :span="4" :xs="12" :sm="12" :md="6" :lg="4" v-for="(item, idx) in iconNav" :key="idx">
          <div class="icon-block" :href="item.link" target="_blank">
            <div class="icon-wrapper" :style="iconBgStyle(idx)">
              <el-icon
                  :style="iconStyle(idx)"
                  :size="36"
              >
                <component :is="item.icon"/>
              </el-icon>
            </div>
            <div class="label-text">{{ item.label }}</div>
          </div>
        </el-col>
      </el-row>

      <!-- 4. 时间轴图文显示 -->
      <div class="section-title">时间轴</div>
      <el-timeline>
        <el-timeline-item
            v-for="(item, idx) in timelineList"
            :key="idx"
            :timestamp="item.time"
            :color="item.color"
        >
          <div class="timeline-title">{{ item.title }}</div>
          <div class="timeline-content">{{ item.content }}</div>
        </el-timeline-item>
      </el-timeline>

      <!-- 5. 可交互表格 -->
      <div class="section-title">信息资源表格</div>
      <el-table :data="tableData" style="width: 100%" class="custom-table">
        <el-table-column prop="resourceName" label="名称" sortable align="center"/>
        <el-table-column prop="resourceType" label="类型" align="center">
          <template #default="scope">
            <el-tag :type="getTagType(scope.row.resourceType)">{{ scope.row.resourceType }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="date" label="日期" sortable align="center"/>
        <el-table-column prop="description" label="描述" align="center">
          <template #default="scope">
            <el-tooltip
                effect="light"
                :content="scope.row.description"
                placement="top"
                :disabled="!isTextOverflow(scope.row.description)"
            >
              <div class="cell-content">
                {{ scope.row.description }}
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center">
          <template #default="scope">
            <el-button size="small" type="primary" link @click="handleView(scope.row)">查看</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination-container">
        <el-pagination
            background
            layout="prev, pager, next"
            :current-page="currentPage"
            :page-size="pageSize"
            :total="total"
            @current-change="handleCurrentChange"
        />
      </div>
    </div>
  </div>
</template>

<style scoped>
.app-bg {
  min-height: 100vh;
  width: 100%;
  display: flex;
  flex-direction: column;
  padding: 0;
  position: relative;
  justify-content: space-between;
}

.topic-info {
  min-height: 100vh;
  width: 100%;
  margin: 0 auto;
  border-radius: 0 0 16px 16px;
  padding: 36px 32px 48px 32px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.section-title {
  font-size: 22px;
  font-weight: bold;
  padding-left: 8px;
  border-left: 4px solid #409eff;
  background: #f7faff;
  line-height: 1.8;
}

.carousel-img-wrapper {
  position: relative;
  width: 100%;
  height: 320px;
}

.carousel-img {
  width: 100%;
  height: 100%;
  border-radius: 8px;
}

.carousel-caption {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  padding: 14px;
  font-size: 18px;
  border-radius: 0 0 8px 8px;
}

.mixed-img {
  width: 100%;
  height: 140px;
  object-fit: cover;
  border-radius: 6px;
}

.mixed-title {
  font-size: 17px;
  font-weight: 600;
  margin: 10px 0 4px 0;
}

.mixed-desc {
  color: #666;
  font-size: 15px;
}

.el-card {
  margin-bottom: 24px;
  border-radius: 12px;
  transition: all 300ms ease;
  cursor: pointer;
}

.el-card:hover {
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  transform: translateY(-4px);
  transition: all 300ms ease;
}

.icon-nav {
  text-align: center;
  row-gap: 24px;
}

.icon-nav .icon-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: all 300ms ease;
}

.icon-nav .icon-block .icon-wrapper {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-content: center;
}

.icon-nav .icon-block .label-text {
  white-space: nowrap;
}

.el-icon {
  height: auto;
}

.icon-nav .icon-block:hover {
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  transform: translateY(-4px);
  transition: all 300ms ease;
}

.pagination-container .el-pagination {
  float: right;
}

.icon-nav .el-icon {
  margin-bottom: 6px;
}

.timeline-title {
  font-weight: 600;
  font-size: 17px;
}

.timeline-content {
  color: #666;
  font-size: 15px;
}

@media (max-width: 1199px) {
  .el-col-md-12 {
    flex: 0 0 50%;
    max-width: 50%;
  }
}

@media (max-width: 900px) {
  .el-col-lg-8 {
    flex: 0 0 100%;
    max-width: 100%;
  }

  .topic-info {
    padding: 12px 2vw 24px 2vw;
    max-width: 100%;
    border-radius: 0;
  }

  .carousel-img-wrapper, .carousel-img {
    min-height: 120px;
  }
}

@media (max-width: 767px) {
  .el-col-sm-24 {
    flex: 0 0 100%;
    max-width: 100%;
  }
}

@media (hover: hover) {
  a:hover {
    background-color: #409eff;
  }
}

.el-button:hover {
  background-color: #409eff;
  color: #fff;
}

.custom-table {
  border-radius: 8px;
  /* 去掉边框线 */
  border: none;
  /* 去掉内边框线 */
  --el-table-border: none;
  --el-table-border-color: transparent;
}

.custom-table .el-table__header th {
  background-color: #f5f7fa;
  color: #333;
  font-weight: 600;
  height: 50px;
  /* 表头文字居中 */
  text-align: center;
}

.custom-table .el-table__body tr:hover td {
  background-color: #f5f7fa !important;
}

.custom-table .el-table__cell {
  padding: 12px 0;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

:deep(.custom-table .el-table__cell .cell) {
  /* 多行文本显示省略号
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  line-height: 1.5;*/

  /*单行文本显示省略号*/
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* 去掉表格内部边框线 */
.custom-table .el-table__inner-wrapper::before {
  display: none;
}

/* 标签样式调整 */
.custom-table .el-tag {
  margin: 0 2px;
}

/* 页脚基础样式 */
.app-footer {
  background-color: #2c3e50;
  color: #ecf0f1;
  padding: 40px 0 20px;
  margin-top: 60px;
  width: 100%;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
}
</style>
